﻿//-----------------------------------------------------------------------------------
// Web test plugin to dynamically correlate parameters in a CRM4 reporting page.
// Copyright(c) Microsoft Corporation, 2009
//-----------------------------------------------------------------------------------

using System;
using Microsoft.VisualStudio.TestTools.WebTesting;
using Microsoft.VisualStudio.TestTools.WebTesting.Rules;

namespace WebAndLoadTestPluginsAndRules.WebTestPlugins
{

    [System.ComponentModel.DisplayName("CRM4Correlation")]
    [System.ComponentModel.Description("Provides automatic parameter correlation for CRM4 report viewer")]
    public class CRM4Correlation : WebTestPlugin
    {
        public CRM4Correlation() { }

        private bool IsReportControlRequest(WebTestRequest r)
        {
            return r.Url.Contains("ReportViewerWebControl.axd");
        }

        private bool IsReportViewerRequest(WebTestRequest r)
        {
            try
            {
                if (!r.Url.Contains("reportviewer.aspx"))
                    return false;
                FormPostHttpBody postBody = (FormPostHttpBody)r.Body;
                if (postBody != null)
                {
                    foreach (FormPostParameter p in postBody.FormPostParameters)
                    {
                        if (p.Name.StartsWith("ReportViewer"))
                            return true;
                    }
                }
            }
            // Eat any exceptions
            catch (Exception e)
            {
            }
            return false;

        }

        /// <summary>
        /// Method to replace a part of a string with a new value.
        /// For example, if string = "Foo=FooValue&Bar=BarValue", and you call
        /// ReplaceStringPart("Foo=FooValue&Bar=BarValue", "Foo=", "&", "{{Foo}}")
        /// you will get Foo={{Foo}}&Bar=BarValue
        /// Note that every occurence is replaced. E.g. 
        /// ReplaceStringPart("Foo=FooValue&Bar=BarValueFooValue", "Foo=", "&", "{{Foo}}")
        /// you will get Foo={{Foo}}&Bar=BarValue{{Foo}}
        /// </summary>
        /// <param name="s">string to modify</param>
        /// <param name="startsWith">string to replace starts with this</param>
        /// <param name="endsWith">string to replace ends with this</param>
        /// <param name="newValue">new value to set</param>
        public static void ReplaceStringPart(string s, string startsWith, string endsWith, string newValue)
        {
            int startIndex = s.IndexOf(startsWith) + startsWith.Length;
            if (startIndex == -1)
                return; // probably should throw
            int endIndex = s.IndexOf(endsWith, startIndex);
            string replaceValue = s.Substring(startIndex, endIndex - startIndex);
            s.Replace(replaceValue, newValue);
        }

        // This method will parameterize the ReportSession and ControlID parts in the ReportUrl parameter
        // This value of this param will be of the form
        // ReportUrl=%2fReserved.ReportViewerWebControl.axd%3fReportSession%3deptsrp55zvb1m0ygfwzwqv45%26ControlID%3dcb144ce0-3f5a-4be0-89c6-f41ca05a9226%26Culture%3d1033%26UICulture%3d1033%26ReportStack%3d1%26OpType%3dReportArea%26Controller%3dClientControllerreportViewer%26PageNumber%3d1%26ZoomMode%3dPercent%26ZoomPct%3d100%26ReloadDocMap%3dtrue%26EnableFindNext%3dFalse%26LinkTarget%3d_blank
        // It will be parameterized to
        // ReportUrl=%2fReserved.ReportViewerWebControl.axd%3fReportSession%3{{ReportSession}}%26ControlID%3d{{ControlID}}%26Culture%3d1033%26UICulture%3d1033%26ReportStack%3d1%26OpType%3dReportArea%26Controller%3dClientControllerreportViewer%26PageNumber%3d1%26ZoomMode%3dPercent%26ZoomPct%3d100%26ReloadDocMap%3dtrue%26EnableFindNext%3dFalse%26LinkTarget%3d_blank
        private void BindReportUrl(string reportUrlQueryStringParameterValue)
        {
            
            // Replace ReportSession part
            ReplaceStringPart(reportUrlQueryStringParameterValue, "ReportSession%3d", "%26", "{{ReportSession}}");
            ReplaceStringPart(reportUrlQueryStringParameterValue, "ControlID%3d", "%26", "{{ControlID}}");
        }

        /// <summary>
        /// Fires before each web page request
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public override void PreRequest(object sender, PreRequestEventArgs e)
        {
            if (IsReportViewerRequest(e.Request))
            {
                ExtractText extractReportSession = new ExtractText();
                extractReportSession.StartsWith = "ReportSession=";
                extractReportSession.EndsWith = "&";
                extractReportSession.ContextParameterName = "ReportSession";
                e.Request.ExtractValues += new EventHandler<ExtractionEventArgs>(extractReportSession.Extract);

                ExtractText extractControlID = new ExtractText();
                extractControlID.StartsWith = "ControlID=";
                extractControlID.EndsWith = "&";
                extractControlID.ContextParameterName = "ControlID";
                e.Request.ExtractValues += new EventHandler<ExtractionEventArgs>(extractControlID.Extract);
            }
            // Bind the ReportUrl, ReportSession, and ControlID parameters
            if (IsReportControlRequest(e.Request))
            {
                foreach (QueryStringParameter p in e.Request.QueryStringParameters)
                {
                    if (p.Name.Equals("ReportSession"))
                    {
                        p.Value = "{{ReportSession}}";
                    }
                    if (p.Name.Equals("ControlID"))
                    {
                        p.Value = "{{ControlID}}";
                    }
                    if (p.Name.Equals("ReportUrl"))
                    {
                        BindReportUrl(p.Value);
                    }
                }
            }
        }
    }
}